<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>MyBatis 代码生成器</title>

    <!-- 本地 Bootstrap CSS -->
    <link href="/css/bootstrap.min.css" rel="stylesheet">

    <!-- 本地 Bootstrap Icons -->
    <link href="/css/bootstrap-icons.min.css" rel="stylesheet">

    <!-- 自定义样式 -->
    <style>
        .form-card {
            background: #f8f9fa;
            border-radius: 15px;
            box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
        }
        .table-list {
            max-height: 400px;
            overflow-y: auto;
        }
        .generate-btn {
            background: linear-gradient(45deg, #4e73df, #224abe);
            border: none;
            transition: all 0.3s;
        }
        .generate-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 0.5rem 1rem rgba(78, 115, 223, 0.4);
        }

        .table-hover tbody tr:hover {
            background-color: rgba(78, 115, 223, 0.05);
        }
        .font-monospace {
            font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace;
        }
    </style>
</head>
<body class="bg-light">
    <div class="container py-5">
        <!-- 标题 -->
        <div class="text-center mb-5">
            <h1 class="display-4 text-primary fw-bold">
                <i class="bi bi-gear-wide-connected"></i>
                MyBatis 代码生成器
            </h1>
            <p class="lead text-muted">可视化数据库代码生成工具</p>
        </div>

        <!-- 主卡片 -->
        <div class="card form-card mx-auto">
            <div class="card-body p-4">
                <!-- 数据库连接表单 -->
                <form id="dbForm" class="row g-3 mb-4">
                    <div class="col-md-6">
                        <label class="form-label">JDBC URL</label>
                        <input type="text"
                               class="form-control form-control-lg"
                               id="jdbcUrl"
                               placeholder="jdbc:mysql://host:port/dbname">
                    </div>
                    <div class="col-md-3">
                        <label class="form-label">用户名</label>
                        <input type="text"
                               class="form-control form-control-lg"
                               id="username">
                    </div>
                    <div class="col-md-3">
                        <label class="form-label">密码</label>
                        <input type="password"
                               class="form-control form-control-lg"
                               id="password">
                    </div>

                    <div class="col-12 text-end">
                        <button type="button"
                                class="btn btn-primary btn-lg px-4"
                                onclick="testConnection()">
                            <i class="bi bi-plug me-2"></i> 测试连接
                        </button>
                    </div>
                </form>

                <!-- 表格展示区 -->
                <div id="tableSection" class="d-none mt-4">
                    <div class="card">
                        <div class="card-header bg-primary text-white">
                            <h5 class="mb-0">
                                <i class="bi bi-table"></i> 数据库表列表
                                <small id="tableCount" class="float-end"></small>
                            </h5>
                        </div>

                        <div class="card-body p-0">
                            <div class="table-responsive">
                                <table class="table table-hover align-middle mb-0">
                                    <thead class="table-list">
                                        <tr>
                                            <th width="50">
                                                <input type="checkbox" id="selectAll" />
                                            </th>
                                            <th>表名称</th>
                                            <th width="120">记录数</th>
                                            <th width="200">更新时间</th>
                                        </tr>
                                    </thead>
                                    <tbody id="tableBody">
                                        <!-- 数据动态插入 -->
                                    </tbody>
                                </table>
                            </div>
                        </div>

                        <div class="card-footer bg-transparent">
                            <button class="btn generate-btn btn-lg text-white w-100" onclick="generateCode()">
                                <i class="bi bi-file-earmark-zip me-2"></i> 生成选中表的代码
                            </button>
                        </div>
                    </div>
                </div>

                <!-- 新增进度条 HTML -->
                <div class="progress mt-3" id="downloadProgressBar" style="height: 20px; display: none;">
                    <div class="progress-bar progress-bar-striped progress-bar-animated"
                         id="downloadProgress"
                         role="progressbar"
                         style="width: 0%"
                         aria-valuenow="0"
                         aria-valuemin="0"
                         aria-valuemax="100">
                    </div>
                </div>

                <!-- 修改加载指示器 -->
                <div id="loading" class="text-center mt-4 d-none">
                    <div class="spinner-border text-primary" role="status"></div>
                    <p class="text-muted mt-2">正在生成代码... <span id="progressText">0%</span></p>
                    <div class="progress mt-2" style="height: 5px;">
                        <div class="progress-bar" id="loadingProgress" style="width: 0%"></div>
                    </div>
                </div>

                <!-- 状态提示 Toast -->
                <div class="toast-container position-fixed bottom-0 end-0 p-3">
                    <div id="liveToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
                        <div class="toast-header">
                            <strong class="me-auto">系统提示</strong>
                            <button type="button" class="btn-close" data-bs-dismiss="toast"></button>
                        </div>
                        <div class="toast-body"></div>
                    </div>
                </div>

            </div>
        </div>
    </div>

<!-- 本地 Bootstrap JS -->
<script src="/js/bootstrap.bundle.min.js"></script>
<script>
    // 动态渲染表格
    function renderTable(tables) {
        const tbody = document.getElementById('tableBody')
        const countBadge = document.getElementById('tableCount')

        // 清空现有内容
        tbody.innerHTML = tables.map(table => `
            <tr>
                <td>
                    <input type="checkbox"
                           name="table"
                           value="${table.name}"
                           class="form-check-input">
                </td>
                <td>
                    <div class="d-flex align-items-center">
                        <i class="bi bi-table me-2"></i>
                        <span class="font-monospace">${table.name}</span>
                    </div>
                </td>
                <td>${table.rows.toLocaleString()}</td>
                <td>${new Date(table.updateTime).toLocaleString()}</td>
           </tr>
        `).join('');

        // 更新计数
        countBadge.innerHTML = `共 ${tables.length} 张表`

        initCheckbox()
    }

    function initCheckbox() {
        const selectAll = document.getElementById("selectAll");
        const checkboxs = document.querySelectorAll("[name='tab;e']");

        selectAll.onclick = () => {
            checkboxs.forEach(cb => cb.checked = selectAll.checked)
        }

        checkboxs.forEach(cb => {
            cb.onclick = () => {
                if (!cb.checked) selectAll.checked = false;
            }
        })
    }

    // 显示提示消息
    function showToast(message, type = 'info') {
        const toastEl = document.getElementById('liveToast')
        const toastBody = toastEl.querySelector('.toast-body')

        toastEl.classList.remove('bg-info', 'bg-success', 'bg-danger')
        switch(type) {
            case 'success':
                toastEl.classList.add('bg-success', 'text-white')
                break
            case 'error':
                toastEl.classList.add('bg-danger', 'text-white')
                break
            default:
                toastEl.classList.add('bg-info', 'text-white')
        }

        toastBody.textContent = message
        new bootstrap.Toast(toastEl).show()
    }

    // 显示/隐藏加载状态
    function showLoading(show) {
        const loading = document.getElementById('loading')
        loading.classList.toggle('d-none', !show)
    }

    // 修改后的测试连接方法
    async function testConnection() {
        try {
            showLoading(true)

            const response = await fetch('/api/test-connection', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    jdbcUrl: document.getElementById('jdbcUrl').value,
                    username: document.getElementById('username').value,
                    password: document.getElementById('password').value
                })
            })

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`)
            }

            const tables = await response.json()
            document.getElementById('tableSection').classList.remove('d-none')
            renderTable(tables.data)
            showToast('连接成功，已加载表列表', 'success')

        } catch (error) {
            showToast(`连接失败: ${error.message}`, 'error')
        } finally {
            showLoading(false)
        }
    }

    // 新增状态变量
    let downloadProgress = 0;
    let isDownloading = false;
    let retryCount = 0;
    const MAX_RETRY = 3;

    // 生成代码（优化版）
    async function generateCode() {
        try {
            if (isDownloading) return;

            isDownloading = true;
            showLoading(true);
            updateProgress(0);

            const tables = getSelectedTables();
            const response = await fetchWithRetry('/api/generate', tables);

            if (!response.ok) throw new Error(`HTTP 错误: ${response.status}`);

            // 获取服务器文件哈希
            const serverHash = response.headers.get('X-Content-SHA256');
            const blob = await readStreamWithProgress(response, (progress) => {
                updateProgress(progress);
            });

            // 客户端哈希校验
            const clientHash = await calculateSHA256(blob);
            if (clientHash !== serverHash) {
                throw new Error('文件校验失败，请重新下载');
            }

            // 触发下载
            triggerDownload(blob);
            showToast('下载完成，文件已验证', 'success');

        } catch (error) {
            handleDownloadError(error);
        } finally {
            resetDownloadState();
        }
    }

    // 获取选中表格
    function getSelectedTables() {
        const tables = Array.from(document.querySelectorAll('[name="table"]:checked'))
            .map(input => input.value);
        if (tables.length === 0) throw new Error('请至少选择一张表');
        return tables;
    }

    // 带重试的 Fetch
    async function fetchWithRetry(url, tables) {
        let attempt = 0;
        while (attempt < MAX_RETRY) {
            try {
                const response = await fetch(url, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        jdbcUrl: document.getElementById('jdbcUrl').value,
                        username: document.getElementById('username').value,
                        password: document.getElementById('password').value,
                        tables: tables
                    })
                });
                if (response.ok) return response;
                throw new Error(`请求失败: ${response.status}`);
            } catch (error) {
                if (++attempt === MAX_RETRY) throw error;
                await new Promise(resolve => setTimeout(resolve, 2000));
            }
        }
    }

    // 带进度条的流读取
    async function readStreamWithProgress(response, progressCallback) {
        const reader = response.body.getReader();
        const contentLength = +response.headers.get('Content-Length');
        let receivedLength = 0;
        const chunks = [];

        while(true) {
            const { done, value } = await reader.read();
            if (done) break;

            chunks.push(value);
            receivedLength += value.length;
            const progress = Math.round((receivedLength / contentLength) * 100);
            progressCallback(progress);
        }

        return new Blob(chunks);
    }

    // SHA-256 计算
    async function calculateSHA256(blob) {
        const buffer = await blob.arrayBuffer();
        const hashArray = await crypto.subtle.digest('SHA-256', buffer);
        return Array.from(new Uint8Array(hashArray))
            .map(b => b.toString(16).padStart(2, '0'))
            .join('');
    }

    // 触发文件下载
    function triggerDownload(blob) {
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `mybatis-code-${Date.now()}.zip`;
        document.body.appendChild(a);
        a.click();
        URL.revokeObjectURL(url);
        a.remove();
    }

    // 错误处理
    function handleDownloadError(error) {
        console.error('下载失败:', error);

        if (retryCount < MAX_RETRY) {
            retryCount++;
            showToast(`${error.message} (${retryCount}/3 重试中...)`, 'warning');
            setTimeout(generateCode, 2000);
        } else {
            showToast(`下载失败: ${error.message}`, 'error');
            retryCount = 0;
        }
    }

    // 重置状态
    function resetDownloadState() {
        isDownloading = false;
        showLoading(false);
        updateProgress(0);
    }

    // 更新进度条
    function updateProgress(percent) {
        downloadProgress = percent;
        const progressBar = document.getElementById('downloadProgress');
        if (progressBar) {
            progressBar.style.width = `${percent}%`;
            progressBar.setAttribute('aria-valuenow', percent);
        }
    }

</script>
</body>
</html>